package db

import (
	"fmt"

	"github.com/micro-plat/hydra"
	"github.com/micro-plat/lib4go/db"
	"github.com/micro-plat/lib4go/errs"

	"gitee.com/micro-plat/qtask/internal/modules/const/conf"
	"gitee.com/micro-plat/qtask/internal/modules/const/field"
	"gitee.com/micro-plat/qtask/internal/modules/const/sql"
	"gitee.com/micro-plat/qtask/internal/modules/const/xerr"
	"github.com/micro-plat/lib4go/jsons"
	"github.com/micro-plat/lib4go/types"
)

// Processing 开始处理任务
func Processing(db db.IDBExecuter, taskID int64) error {
	imap := map[string]interface{}{
		field.TaskID: taskID,
	}
	row, err := db.Execute(sql.SQLProcessingTask, imap)
	if err != nil || row != 1 {
		return fmt.Errorf("修改任务为处理中(%d)失败 %v", taskID, err)
	}
	return nil
}

// Finish 结束任务
func Finish(db db.IDBExecuter, taskID int64) error {
	imap := map[string]interface{}{
		field.TaskID: taskID,
	}
	_, err := db.Execute(sql.SQLFinishTask, imap)
	if err != nil {
		return fmt.Errorf("关闭任务(%d)失败 %v", taskID, err)
	}
	return nil
}

// SaveTask 创建任务
func SaveTask(db db.IDBExecuter, name, orderNO string, input map[string]interface{}, timeout int, mq string, args map[string]interface{}) (taskID int64, err error) {

	// 构建参数
	imap, taskID, err := buildParam(db, name, orderNO, input, timeout, mq, args)
	if err != nil {
		return 0, fmt.Errorf("构建参数异常,err:%v", err)
	}

	//增加重复检查，当相同信息的数据存在，且状态为20,30时，则不再添加新数据
	v, err := db.Scalar(sql.SQLQueryTaskForInsert, imap)
	if err != nil {
		return 0, fmt.Errorf("创建任务(%s)失败 %v", name, err)
	}
	if taskid := types.GetInt64(v); taskid > 0 {
		imap[field.TaskID] = taskid
		input[field.TaskID] = taskid
		buff, err := jsons.Marshal(input)
		if err != nil {
			return 0, fmt.Errorf("任务输入参数转换为json失败:%v(%+v)", err, input)
		}
		imap[field.MsgContent] = string(buff)
		row, err := db.Execute(sql.SQLTaskRepeat, imap)
		if err != nil {
			return 0, fmt.Errorf("重复任务处理操作数据库失败,name:%v,err:%v,row:%v", name, err, row)
		}

		return taskid, nil
	}

	//保存任务信息
	row, err := db.Execute(sql.SQLCreateTask, imap)
	if err != nil || row != 1 {
		return 0, fmt.Errorf("创建任务(%s)失败 %v", name, err)
	}
	return types.GetInt64(taskID), nil
}

func CloseTask(db db.IDBExecuter) error {
	// 失败任务处理
	if err := failedTasks(db, sql.SQLFailedTask); err != nil {
		return err
	}
	return nil
}

// ClearTask 清除任务
func ClearTask(db db.IDBExecuter) error {

	// 清除序列表
	if err := clearSeq(db); err != nil {
		return err
	}

	_, err := db.Execute(sql.SQLClearTask, nil)
	if err != nil {
		return fmt.Errorf("清理任务失败 %v", err)
	}

	return nil
}

// query 查询执行任务
func query(db db.IDBExecuter, SQLGetBatch string, SQLUpdateTask string, SQLQueryWaitProcess string) (batchID int64, rows db.QueryRows, err error) {
	imap := map[string]interface{}{
		field.Name: "获取任务列表",
	}

	//获取任务编号
	batchID, err = getNewID(db, SQLGetBatch, imap)
	if err != nil {
		return 0, nil, err
	}

	imap[field.BatchID] = batchID
	imap[field.PlatName] = conf.GetPlatName()

	row, err := db.Execute(SQLUpdateTask, imap)
	if err != nil {
		return 0, nil, fmt.Errorf("修改任务批次失败 %v", err)
	}
	if row == 0 {
		return 0, nil, nil
	}
	rows, err = db.Query(SQLQueryWaitProcess, imap)
	if err != nil {
		return 0, nil, fmt.Errorf("根据批次查询任务失败 %v", err)
	}
	return batchID, rows, nil
}

// failedTasks 失败任务处理
func failedTasks(db db.IDBExecuter, SQLFailedTask string) error {
	_, err := db.Execute(SQLFailedTask, nil)
	if err != nil {
		return fmt.Errorf("修改失败任务批次发生异常,err:%v", err)
	}
	return nil
}

// QueryTasks 查询任务
func QueryTasks(db db.IDBExecuter) (rows db.QueryRows, err error) {

	// 查询正在执行任务
	_, rows, err = query(db, sql.SQLGetSEQ, sql.SQLUpdateTask, sql.SQLQueryWaitProcess)
	if err != nil {
		return nil, err
	}
	return rows, nil
}

// Close 关闭任务
func Close(taskID int64) error {

	input := map[string]interface{}{field.TaskID: taskID}
	db := hydra.C.DB().GetRegularDB(conf.DBName)

	count, err := db.Scalar(sql.SQLQueryTaskByID, input)
	if err != nil {
		return errs.NewErrorf(400, "查询任务操作数据库异常,err:%v", err)
	}

	if types.GetInt(count) == 0 {
		return xerr.TaskNotExistError
	}
	row, err := db.Execute(sql.SQLClosetask, input)
	if err != nil {
		return errs.NewErrorf(400, "关闭任务,数据库操作异常,err:%v,task_id:%v", err, taskID)
	}
	if row == 0 {
		return errs.NewErrorf(204, "关闭任务,任务已结束,taks_id:%v", taskID)
	}
	return nil
}

// Update 更新任务
func Update(taskID int64, input types.XMap) error {

	db := hydra.C.DB().GetRegularDB(conf.DBName)

	// 查询任务
	input[field.TaskID] = taskID
	count, err := db.Scalar(sql.SQLQueryTaskByID, input)
	if err != nil {
		return errs.NewErrorf(400, "查询任务操作数据库异常,err:%v", err)
	}

	if types.GetInt(count) == 0 {
		return xerr.TaskNotExistError
	}

	// 更新任务
	row, err := db.Execute(sql.SQLUpdateTaskByTaskID, input)
	if err != nil {
		return errs.NewErrorf(400, "更新任务,数据库操作异常,err:%v,task_id:%v", err, taskID)
	}
	if row != 1 {
		return errs.NewErrorf(204, "更新任务,任务已结束,taks_id:%v", taskID)
	}
	return nil
}

func buildParam(db db.IDBExecuter, name, orderNO string, input map[string]interface{}, timeout int, mq string, args map[string]interface{}) (types.XMap, int64, error) {
	imap := map[string]interface{}{
		field.Name:    name,
		field.OrderNo: orderNO,
	}
	for k, v := range args {
		imap[k] = v
	}
	//获取任务编号
	taskID, err := getNewID(db, sql.SQLGetSEQ, imap)
	if err != nil {
		return nil, 0, fmt.Errorf("获取任务(%s)编号失败 %v", name, err)
	}
	//处理任务参数
	input[field.TaskID] = taskID
	buff, err := jsons.Marshal(input)
	if err != nil {
		return nil, 0, fmt.Errorf("任务输入参数转换为json失败:%v(%+v)", err, input)
	}
	imap[field.MsgContent] = string(buff)
	imap[field.TaskID] = taskID
	imap[field.NextInterval] = timeout
	imap[field.FirstTimeout] = types.DecodeInt(imap[field.FirstTimeout], nil, timeout, imap[field.FirstTimeout])
	imap[field.MaxTimeout] = types.DecodeInt(imap[field.MaxTimeout], nil, 259200, imap[field.MaxTimeout])
	imap[field.DeleteInterval] = types.DecodeInt(imap[field.DeleteInterval], nil, 259200, imap[field.DeleteInterval])
	imap[field.MaxCount] = types.DecodeInt(imap[field.MaxCount], nil, 100, imap[field.MaxCount])
	imap[field.QueueName] = mq
	imap[field.PlatName] = conf.GetPlatName()

	return imap, taskID, nil
}
